package com.wangsd.web.miniapp;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.wangsd.common.basicbean.Result;
import com.wangsd.common.component.WxjavaService;
import com.wangsd.common.utils.ApplicationUtils;
import com.wangsd.common.utils.DateUtils;
import com.wangsd.common.utils.HttpClientUtils;
import com.wangsd.web.MyController;
import com.wangsd.web.face.entity.*;
import com.wangsd.web.face.service.*;
import com.wangsd.web.miniapp.entity.WxPay;
import com.wangsd.web.miniapp.service.WxPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static com.wangsd.common.enums.ResultCode.MINI_APP_PAY_SIGN_PRARM;
import static com.wangsd.common.enums.ResultCode.NO_LOGIN;

/**
 * 小程序业务接口
 */
@Api(value = "小程序业务接口", tags = "小程序业务接口")
@RestController
@RequestMapping("/mini")
@Slf4j
public class MiniAppController extends MyController {

    @Autowired
    MemberService memberService;
    @Autowired
    WxjavaService wxjavaService;
    @Autowired
    MerchantService merchantService;
    @Autowired
    MemberLevelService memberLevelService;
    @Autowired
    MemberAccountDetailService memberAccountDetailService;
    @Autowired
    WxPayService wxPayService;
    @Autowired
    TOrderService tOrderService;
    @Autowired
    RedisTemplate redisTemplate;

    @Value("${service.authApiUrl}")
    private String wechatUrl;

    /*登录token类型,m表示小程序端*/
    public static final String LOGIN_TOKEN_TYPE_M = "M";

    @ApiOperation(value = "微信登录", notes = "微信登录", httpMethod = "GET")
    @RequestMapping("/login")
    public Result login(String code) {
        WxMaService service = wxjavaService.getMiniService(getMiniAppid());
        WxMaJscode2SessionResult data = null;
        try {
            data = service.getUserService().getSessionInfo(code);
            log.debug("小程序登陆获取的信息==" + data);
        } catch (WxErrorException e) {
            log.error("login", e);
        }
        if (data == null) {
            return Result.fail("获取session失败");
        }
        String unionid = data.getUnionid();
        Member member = new Member();
        member.setMiniOpenId(data.getOpenid());
        member.setSessionKey(data.getSessionKey());
        member.setUnionId(unionid);

        String token = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(LOGIN_TOKEN_TYPE_M + token, member, 2, TimeUnit.HOURS);
        Map<String, String> map = new HashMap<>();
        map.put("token", LOGIN_TOKEN_TYPE_M + token);
        return Result.success(map);
    }

    @ApiOperation(value = "手机号码是否保存成功", notes = "手机号码是否保存成功", httpMethod = "GET", response = Result.class)
    @RequestMapping("/isPhone")
    public Result isPhone() {
        Member miniUserInfo = getMiniUserInfo();
        if (miniUserInfo == null) {
            return new Result(NO_LOGIN);
        }
        Member member = memberService.selectByMiniOpenId(miniUserInfo.getMiniOpenId());
        if (member != null && member.getMobile() != null) {
            return Result.success(member);
        } else {
            return Result.fail("未获取手机号");
        }
    }

    /**
     * 保存手机号码
     *
     * @param encryptedData
     * @param ivStr
     * @return
     */
    @ApiOperation(value = "保存手机号码", notes = "保存手机号码", httpMethod = "POST", response = Result.class)
    @PostMapping("/savePhone")
    public Object savePhone(String encryptedData, String ivStr, String phone, String validateCode) {
        Member miniUserInfo = getMiniUserInfo();
        if (miniUserInfo == null) {
            return new Result(NO_LOGIN);
        }
        String sessionKey = miniUserInfo.getSessionKey();
        String openid = miniUserInfo.getMiniOpenId();
        String mobile = null;
        String appid = getMiniAppid();
        String unionId = miniUserInfo.getUnionId();
        if(StringUtils.isBlank(unionId)){
            return Result.fail("商户公众号和小程序关联异常！！");
        }
        Merchant merchant = merchantService.selectByMiniAppId(appid);
        if (phone != null && validateCode != null) {
            String code = (String) redisTemplate.opsForValue().get(phone);
            if (!validateCode.equals(code)) {
                return Result.fail("验证码不正确！");
            }
            mobile = phone;
        } else {
            WxMaService service = wxjavaService.getMiniService(appid);
            WxMaPhoneNumberInfo info = service.getUserService().getPhoneNoInfo(sessionKey, encryptedData, ivStr);
            mobile = info.getPhoneNumber();
        }
        MemberLevel memberLevel = memberLevelService.selectIsDefaultAndMerchantId(1, merchant.getId());
        if (memberLevel == null) {
            return Result.fail("商家未配置会员等级！");
        }
        Member member = new Member();

        member.setMobile(mobile);
        member.setMiniOpenId(openid);
        member.setMerchantId(merchant.getId());
        member.setCode(merchant.getCode());

        if (memberLevel != null) {
            member.setMemberLevelId(memberLevel.getId());
        }
        member.setUseTime(new Date());
        memberService.register(member);

        //生成会员卡号 exp：2018000088000088
        String begin = DateUtils.formatDate(new Date(), "yyyy");
        String dft = "000000";
        String merchantId = merchant.getId().toString();
        String second = dft.substring(0, 6 - merchantId.length()) + merchantId;
        String end = dft.substring(0, 6 - (member.getId().toString()).length()) + member.getId();
        String cardNo = begin + second + end;
        member.setCardNo(cardNo);

        /*保存通过unionId获取的openid*/
        String opend = null;
        try {
            opend = templateMsg(miniUserInfo.getUnionId(), cardNo, merchant);
        } catch (Exception e) {
            log.error("保存通过unionId获取的openid :"+e);
            return e.getMessage();
        }

        if (StringUtils.isNotBlank(opend)) {
            member.setSubOpenId(opend);
        }
        memberService.saveOrUpdate(member);

        return Result.success();
    }

    @ApiOperation(value = "用户信息是否保存成功", notes = "用户信息是否保存成功", httpMethod = "GET", response = Result.class)
    @RequestMapping("/isUserinfo")
    public Result isUserinfo() {
        Member miniUserInfo = getMiniUserInfo();
        if (miniUserInfo == null) {
            return new Result(NO_LOGIN);
        }
        String openid = miniUserInfo.getMiniOpenId();
        Member member = memberService.selectByMiniOpenId(openid);
        if (member != null) {
            Merchant merchant = merchantService.getById(member.getMerchantId());
            member.setMerchant(merchant);
            MemberLevel memberLevel = memberLevelService.getById(member.getMemberLevelId());
            member.setMemberLevel(memberLevel);
            return Result.success(member);
        } else {
            return Result.fail("未获取用户信息");
        }
    }

    @ApiOperation(value = "保存用户信息(头像昵称)", notes = "保存用户信息(头像昵称)", httpMethod = "POST", response = Result.class)
    @PostMapping("/saveUserinfo")
    public Result saveUserinfo(String encryptedData, String ivStr, String birthday) {
        Member miniUserInfo = getMiniUserInfo();
        if (miniUserInfo == null) {
            return new Result(NO_LOGIN);
        }
        String openid = miniUserInfo.getMiniOpenId();
        String sessionKey = miniUserInfo.getSessionKey();
        String appid = getMiniAppid();
        WxMaService service = wxjavaService.getMiniService(appid);
        WxMaUserInfo info = service.getUserService().getUserInfo(sessionKey, encryptedData, ivStr);
        Member member = new Member();
        member.setAvatarUrl(info.getAvatarUrl());
        member.setNickName(info.getNickName());
        member.setMiniOpenId(openid);
        member.setStatus(2);//设置会员状态，表示已授权头像
        member.setGender(info.getGender());
        memberService.register(member);
        return Result.success();
    }

    @ApiOperation(value = "微信支付调用", notes = "微信支付调用", httpMethod = "POST")
    @PostMapping("/wxPay")
    public Result wxPay(@RequestBody WxPay wxPay, HttpServletRequest request) {
        if (StringUtils.isBlank(wxPay.getFee())) {
            return Result.fail("参数不能为空！！");
        }
        String oldFee = wxPay.getFee().trim();
        boolean aDouble = ApplicationUtils.isDouble(oldFee);
        if (!aDouble) {
            return Result.fail("输入值不合法！");
        }

        Integer fee = 0;
        /*包含小数金额*/
        if (oldFee.contains(".")) {
            BigDecimal bigDecimal = new BigDecimal(oldFee);
            BigDecimal multiply = bigDecimal.multiply(new BigDecimal(100));
            fee = multiply.intValue();
            //fee = Integer.valueOf(oldFee.replace(".", ""));
        } else { /*整数金额*/
            fee = Integer.valueOf(oldFee) * 100;
        }

        Member miniUserInfo = getMiniUserInfo();
        if (miniUserInfo == null) {
            return new Result(NO_LOGIN);
        }
        String openid = miniUserInfo.getMiniOpenId();

        Member member = memberService.selectByMiniOpenId(openid);
        if (member == null) {
            return Result.fail("请先进行会员登录！！");
        }

        try {
            Object object = wxPayService.wxPay(getMiniAppid(), openid, fee, request);
            if (object == null) {
                return Result.message(MINI_APP_PAY_SIGN_PRARM);
            }
            return Result.success(object);
        } catch (Exception e) {
            log.error("wxPay", e);
        }

        return Result.message(MINI_APP_PAY_SIGN_PRARM);
    }

    @ApiOperation(value = "微信小程序支付回调通知支付", notes = "微信小程序支付回调通知支付", httpMethod = "GET")
    @RequestMapping(value = "/wxNotify")
    public void wxNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("微信支付回调通知开始");
        try {
            wxPayService.wxNotify(request, response);
        } catch (Exception e) {
            log.error("wxNotify", e);
        }
        log.info("微信支付回调通知结束");
    }

    @ApiOperation(value = "查询余额或积分记录列表", notes = "查询余额或积分记录列表", httpMethod = "POST")
    @PostMapping("/selectPointOrFeeList/{pageNum}/{pageSize}")
    public Result selectPointOrFeeList(@ApiParam(value = "当前页", required = true) @PathVariable("pageNum") Integer pageNum,
                                       @ApiParam(value = "每页大小", required = true) @PathVariable("pageSize") Integer pageSize,
                                       @RequestBody @ApiParam(name = "params", value = "传入json格式") WxPay params) {
        if (StringUtils.isBlank(params.getMobile())) {
            return Result.fail("电话号码不能为空！");
        }
        if (params.getType() == null) {
            return Result.fail("类型不能为空！");
        }
        String miniAppid = getMiniAppid();
        Merchant merchant = merchantService.selectByMiniAppId(miniAppid);
        if (merchant == null) {
            return Result.success();
        }
        params.setMerchantId(merchant.getId());
        IPage<MemberAccountDetail> resultIPage = memberAccountDetailService.selectList(pageNum, pageSize, params);
        return Result.success(resultIPage);
    }

    @ApiOperation(value = "查询消费记录列表", notes = "查询消费记录列表", httpMethod = "POST")
    @PostMapping("/selectConsumeList/{pageNum}/{pageSize}")
    public Result selectConsumeList(@ApiParam(value = "当前页", required = true) @PathVariable("pageNum") Integer pageNum,
                                    @ApiParam(value = "每页大小", required = true) @PathVariable("pageSize") Integer pageSize,
                                    @RequestBody @ApiParam(name = "params", value = "传入json格式") WxPay params) {
        if (StringUtils.isBlank(params.getMobile())) {
            return Result.fail("电话号码不能为空！");
        }
        String miniAppid = getMiniAppid();
        Merchant merchant = merchantService.selectByMiniAppId(miniAppid);
        if (merchant == null) {
            return Result.success();
        }
        params.setMerchantId(merchant.getId());
        IPage<TOrder> resultIPage = tOrderService.selectMiniList(pageNum, pageSize, params);
        return Result.success(resultIPage);
    }


    private String templateMsg(String unionId, String cardNo, Merchant merchant) throws Exception {
        String tempLateUrl = wechatUrl + "/api/follow/getOpenIdByUnionId?unionId=" + unionId;
        String openid = null;
        String result = null;
        try {
            result = HttpClientUtils.get(tempLateUrl);
            log.info(result);
            if (StringUtils.isBlank(result)) {
                return null;
            }
            JSONObject jsonObject = JSONObject.parseObject(result);
            int code = jsonObject.getInteger("code");
            if (code != 200) {
                log.info("通过unionid获取openid失败，不发送模板消息");
                throw new Exception(result);
            }
            openid = (String) jsonObject.get("result");
            if (StringUtils.isBlank(openid)) {
                log.info("openid为空，不发送模板消息");
                throw new Exception(result);
            }
        } catch (Exception e) {
            log.error("获取openid异常", e.getMessage());
            throw new Exception(result);
        }
        /*小程序获取到的openid不为空*/
        if (StringUtils.isNotBlank(openid)) {
            /*注册小程序后，发送模板消息*/
            memberService.sendTemplateMsg(openid, cardNo, unionId, merchant);
        }
        return openid;
    }
}
